﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

// std headers
#include <map>
#include <vector>
#include <string>
#include <cstdint>

// qt headers

// gcmp headers

// custom headers
#include "SelectionHelperBase.h"


namespace gmepgcs
{
    template<typename T>
    class SelectionHelper : public SelectionHelperBase
    {
    public:
        explicit SelectionHelper(QObject *parent = nullptr) :
            SelectionHelperBase(parent),
            m_mpConditions(),
            m_mpItems() {};
        virtual ~SelectionHelper() {};

    public:
        void SetCondition(const std::wstring conditionKey, const std::wstring conditionValue);
        void Add(const std::wstring itemKey, T itemValue);
        void Remove(const std::wstring itemKey);
        void Clear();
        bool Empty();
        int Count();

        template<typename Func>
        std::vector<T> Filtered(Func predicate);

        template<typename Func>
        bool Any(Func predicate);

        template<typename Func>
        bool All(Func predicate);

        std::vector<T> GetSelectedItems();

    private:
        std::map<std::wstring, std::wstring> m_mpConditions;
        std::map<std::wstring, T> m_mpItems;
    };


    template<typename T>
    int gmepgcs::SelectionHelper<T>::Count()
    {
        return (int)m_mpItems.size();
    }

    template<typename T>
    inline void SelectionHelper<T>::SetCondition(const std::wstring conditionKey, const std::wstring conditionValue)
    {
        if (m_mpConditions.find(conditionKey) == m_mpConditions.end())
        {
            m_mpConditions[conditionKey] = conditionValue;
            Clear();
            return;
        }

        if (m_mpConditions[conditionKey] != conditionValue)
        {
            m_mpConditions[conditionKey] = conditionValue;
            Clear();
            return;
        }
    }

    template<typename T>
    inline void SelectionHelper<T>::Add(const std::wstring itemKey, T itemValue)
    {
        m_mpItems[itemKey] = itemValue;
        emit ItemsChanged();
    }

    template<typename T>
    inline void SelectionHelper<T>::Remove(const std::wstring itemKey)
    {
        if (m_mpItems.find(itemKey) == m_mpItems.end())
        {
            return;
        }

        m_mpItems.erase(itemKey);
        emit ItemsChanged();
    }

    template<typename T>
    inline void SelectionHelper<T>::Clear()
    {
        if (m_mpItems.empty())
        {
            return;
        }

        m_mpItems.clear();
        emit ItemsChanged();
        emit ItemsCleared();
    }

    template<typename T>
    inline bool SelectionHelper<T>::Empty()
    {
        return m_mpItems.empty();
    }

    template<typename T>
    inline std::vector<T> SelectionHelper<T>::GetSelectedItems()
    {
        return Filtered([=](T component) {return true; });
    }  

    template<typename T>
    template<typename Func>
    inline std::vector<T> SelectionHelper<T>::Filtered(Func predicate)
    {
        std::vector<T> filtered = std::vector<T>();
        for (auto &itemIterator : m_mpItems)
        {
            if (predicate(itemIterator.second))
            {
                filtered.push_back(itemIterator.second);
            }
        }

        return filtered;
    }

    template<typename T>
    template<typename Func>
    inline bool SelectionHelper<T>::Any(Func predicate)
    {
        for (auto &itemIterator : m_mpItems)
        {
            if (predicate(itemIterator.second))
            {
                return true;
            }
        }

        return false;
    }

    template<typename T>
    template<typename Func>
    inline bool SelectionHelper<T>::All(Func predicate)
    {
        for (auto &itemIterator : m_mpItems)
        {
            if (!predicate(itemIterator.second))
            {
                return false;
            }
        }

        return true;
    }

}